package msgdef

import (
	"reflect"
)

/*
消息管理器
*/
type TypeMgr struct {
	//类型名字进行的反射
	typeMap map[string]*MsgDef
	//消息号进行的反射
	idMap map[uint16]*MsgDef
}

func newTypeMgr() (result *TypeMgr) {
	result = new(TypeMgr)
	result.typeMap = make(map[string]*MsgDef)
	result.idMap = make(map[uint16]*MsgDef)
	return
}

func (this *TypeMgr) RegisterType(name string, id uint16, v IMsg) {
	md := new(MsgDef)
	md.MsgID = id
	md.MsgName = name
	md.Typ = reflect.TypeOf(v).Elem()
	this.idMap[id] = md
	this.typeMap[name] = md
	// md.TypeName = md.Typ.Name()
}

func (this *TypeMgr) GetName(msg IMsg) string {
	return msg.Name()
	// v := reflect.TypeOf(msg).Elem()
	// return v.Name()
	// return proto.MessageName(msg)
}

func (this *TypeMgr) GetMsgIDByName(name string) (uint16, error) {
	if def, ok := this.typeMap[name]; ok {
		return def.MsgID, nil
	}
	return 0, nil
}

// 用名字找结构
func (this *TypeMgr) GetMsgDefByName(name string) (*MsgDef, error) {
	if def, ok := this.typeMap[name]; ok {
		return def, nil
	}
	return nil, ErrDef_Not_Exist_Name.NewErr(nil, name)
}

func (this *TypeMgr) GetMsgDefByID(id uint16) (*MsgDef, error) {
	if def, ok := this.idMap[id]; ok {
		return def, nil
	}
	return nil, ErrDef_Not_Exist_Name.NewErr(nil, id)
}

// GetMsgInfo 根据消息号，获得消息的类型，名称，如果是protobuf消息，获得proto消息的容器
func (this *TypeMgr) GetMsgInfo(msgID uint16) (msgName string, msgContent IMsg, err error) {

	//此处会被多线程调用，不确定会不会有问题
	info, ok := this.idMap[msgID]

	if !ok {
		return "", nil, ErrDef_Not_Exist_ID.NewErr(nil, msgID)
	}

	msg := reflect.New(info.Typ).Interface().(IMsg)
	// TryInitCommonMsg(msg)
	return info.MsgName, msg, nil
}

func (this *TypeMgr) GetTypeNameByID(msgID uint16) string {
	if info, ok := this.idMap[msgID]; ok {
		return info.MsgName
	}
	return ""
}

// IsMsgExist 消息是否存在
func (this *TypeMgr) IsMsgExist(msgID uint16) bool {
	_, ok := this.idMap[msgID]
	return ok
}

// 消息反射体
type MsgDef struct {
	MsgID   uint16
	MsgName string
	// TypeName string
	Typ reflect.Type
}

func (this *MsgDef) New() interface{} {
	return reflect.New(this.Typ).Interface()
}
